/**************************************************************************
 * simpletun.c                                                            *
 *                                                                        *
 * A simplistic, simple-minded, naive tunnelling program using tun/tap    *
 * interfaces and TCP. DO NOT USE THIS PROGRAM FOR SERIOUS PURPOSES.      *
 *                                                                        *
 * You have been warned.                                                  *
 *                                                                        *
 * (C) 2010 Davide Brini.                                                 *
 *                                                                        *
 * DISCLAIMER AND WARNING: this is all work in progress. The code is      *
 * ugly, the algorithms are naive, error checking and input validation    *
 * are very basic, and of course there can be bugs. If that's not enough, *
 * the program has not been thoroughly tested, so it might even fail at   *
 * the few simple things it should be supposed to do right.               *
 * Needless to say, I take no responsibility whatsoever for what the      *
 * program might do. The program has been written mostly for learning     *
 * purposes, and can be used in the hope that is useful, but everything   *
 * is to be taken "as is" and without any kind of warranty, implicit or   *
 * explicit. See the file LICENSE for further details.                    *
 *************************************************************************/

#define TUN2FILE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#ifndef TUN2FILE
	#include <sys/inotify.h>

/* 	size of the event structure, not counting name */
	#define EVENT_SIZE  ( sizeof (struct inotify_event) )
	#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
#endif

/* buffer for reading from tun/tap interface, must be >= 1500 */
#define BUFFER_SIZE 1500

int debug;
char *progname;

/**************************************************************************
 * tun_alloc: allocates or reconnects to a tun/tap device. The caller     *
 *            must reserve enough space in *dev.                          *
 **************************************************************************/
int tun_alloc(char *dev, int flags) {
	struct ifreq ifr;
	int fd, err;
	char clonedev[100];

	strcpy(clonedev,"/dev/net/tun");
	if( (fd = open(clonedev , O_RDWR)) < 0 ) {
		perror("Opening /dev/net/tun");
		return fd;
	}

	memset(&ifr, 0, sizeof(ifr));

	ifr.ifr_flags = flags;

	if (*dev) {
		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
	}

	if( (err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) {
		perror("ioctl(TUNSETIFF)");
		close(fd);
		return err;
	}

	strcpy(dev, ifr.ifr_name);
	return fd;
}

int main(void) {
	char tun_name[IFNAMSIZ];
	int tun_fd ;
	int nread;
	char buffer[BUFFER_SIZE] ;
	FILE *pFile ;

#ifndef TUN2FILE
	char ev_buffer[EVENT_BUF_LEN];
	int length, i = 0;
	int fd;
	int wd;
#endif

/* 	Switch for the code that reads the  data from a TUN interface and writes it to a file. */
#ifdef TUN2FILE
/* 	Connect to the TUN device */
	strcpy(tun_name, "tun77");
	tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI);  /* tun interface */
	if(tun_fd < 0) { perror("Error allocating tun/tap interface");	exit(1);  }
	else  printf("Interface opened for reading %s(%d)\n",tun_name,tun_fd);
#else
/*	Switch for the code that gets triggered when a file is updated that read the data and writes it to the TUN interface. */
/* 	Connect to the TUN device */
    strcpy(tun_name, "tun78");
	tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI);  /* tun interface */
	if(tun_fd < 0){	perror("Error allocating tun/tap interface");	exit(1);  }
	else  printf("Interface opened for reading %s(%d)\n",tun_name,tun_fd);

/*	creating the INOTIFY instance*/
	fd = inotify_init();
    if ( fd < 0 ) {	perror( "inotify_init" ); 	exit(1);  }
	else  {   printf("inotify_init %d\n",fd);   }

/*	adding the “/tunwrite.bin” file into watch list. */
	wd = inotify_add_watch(fd, "/home/vamshi/workspace/Tun2File2Tun/src/tunwrite.bin", IN_ACCESS | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE | IN_CREATE |IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_OPEN );
	if(wd < 0) {perror("Error inotify_add_watch");	exit(1);  }
	else  {   printf("inotify_add_watch %d\n",wd);   }

#endif

	/* Now read data coming from the kernel */
	while(1)
	{
#ifdef TUN2FILE
/* 		Read the tun buffer for data.  */
		nread = read(tun_fd,buffer,sizeof(buffer));
		if(nread < 0) {  perror("Error reading from tun/tap interface");  close(tun_fd); exit(1); }
		else	printf("Read %d bytes from device %s\n", nread, tun_name);

/*		Write the data read on the buffer to a file. */
		pFile = fopen ("tunwrite.bin","w+");
		fwrite(buffer, sizeof(unsigned char), nread, pFile);
		fclose (pFile);
#else
		/*		read to determine the event change happens on “/tmp” directory. Actually this read blocks until the change event occurs*/
				length = read( fd, ev_buffer, EVENT_BUF_LEN );
		/*		checking for error. */
				if ( length < 0 ) {   perror( "read" );		exit(1);	}
				else	printf("length of event %d \n",length);


		i = 0 ;
/*		actually read return the list of change events happens. Here, read the change event one by one and process it accordingly.*/
		while ( i < length )
		{
			struct inotify_event *event = ( struct inotify_event * ) &ev_buffer[ i ];
			if ( ( event->mask & IN_ACCESS ) |
						( event->mask & IN_ATTRIB  ) |
						( event->mask &  IN_CLOSE_WRITE  ) |
						( event->mask &  IN_CLOSE_NOWRITE  ) |
						( event->mask &  IN_CREATE  ) |
						( event->mask & IN_DELETE  ) |
						( event->mask &  IN_DELETE_SELF  ) |
						( event->mask &  IN_MODIFY  ) |
						( event->mask &  IN_MOVE_SELF  ) |
						( event->mask &  IN_MOVED_FROM  ) |
						( event->mask &  IN_MOVED_TO  ) |
						( event->mask &  IN_OPEN ) )
				{
					printf( "File modified %s .\n", event->name );
					pFile = fopen ("/home/vamshi/workspace/EthTapFile/src/tunwrite.bin","r+");
					nread = fread(buffer, sizeof(unsigned char), 1500, pFile);
			        fclose (pFile);
			        nread = write(tun_fd,buffer,nread);
			        printf("writing %d bytes from device %s\n", nread, tun_name);
			}
			else
				printf( "File not modified %s .\n", event->name );
		   i += EVENT_SIZE + event->len;
	   }
#endif
	}
#ifndef TUN2FILE
/*	removing the file from the watch list.*/
	inotify_rm_watch( fd, wd );

	/*closing the INOTIFY instance*/
	close( fd );
#endif
	printf("\n");
	return(0);
}
